package im.oen.boot.api.dispatch.handler;

import im.oen.boot.api.annotation.handler.MethodAroundHandler;
import im.oen.boot.api.dao.AbsDao;
import im.oen.boot.api.entity.AbsEntity;
import im.oen.boot.common.utils.JsonUtil;
import im.oen.boot.common.utils.ReflectUtil;

import javax.persistence.Id;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Optional;

/**
 * @author Kevin.Xu
 */
public class FindByIdMethodHandler implements MethodHandler {
    @Override
    public String cmd() {
        return "findById";
    }

    @Override
    public <T extends AbsEntity, ID extends Serializable> Object handler(AbsDao<T, ID> dao, MethodAroundHandler<T> methodAroundHandler, Class<T> entity, String[] paths, String body) {
        boolean emptyHandler = methodAroundHandler == null;
        T obj = JsonUtil.safeToObj(body, entity);
        if (!emptyHandler) {
            methodAroundHandler.findByIdBefore(obj);
        }
        T res = null;

        ID id = this.fetchId(obj);
        if (id == null) {
            res = null;
        } else {
            Optional<T> data = dao.findById(id);
            if (data.isPresent()) {
                res = data.get();
            }
        }
        if (!emptyHandler) {
            methodAroundHandler.findByIdAfter(res);
        }
        return res;
    }

    private <ID> ID fetchId(Object obj) {
        try {
            List<Field> fields = ReflectUtil.fetchFields(obj.getClass());
            for (Field field : fields) {
                Id id = field.getAnnotation(Id.class);
                if (id != null) {
                    field.setAccessible(true);
                    return (ID) field.get(obj);
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }
}
